package com.ywd.platform.netty.jt080.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.ywd.platform.netty.jt080.dto.TerminalRegisterDto;
import com.ywd.platform.netty.jt080.po.CommonResponseBody;
import com.ywd.platform.netty.jt080.po.TerminalRegisterResult;
import com.ywd.platform.netty.jt080.po.*;
import com.ywd.platform.netty.jt080.util.JT808BodyPropsUtil;
import com.ywd.platform.vo.DeviceVo;
import io.netty.channel.*;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;

/**
 * JT808协议服务端处理器
 * 处理终端设备的各种消息并返回响应
 * 功能：
 * 1. 处理终端注册/鉴权
 * 2. 解析位置信息并存储
 * 3. 管理设备连接状态
 * 4. 实现心跳机制
 */
@AllArgsConstructor
@Slf4j
//@ChannelHandler.Sharable
//@Component
public class JT808ServerHandler extends SimpleChannelInboundHandler<JT808Message> {

    private final TerminalService terminalService;
    private final TerminalConnectionManager connectionManager; // 添加连接管理器


    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        InetSocketAddress remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress();
        log.info("设备连接建立 - 远程地址: {}:{}", remoteAddress.getHostString(), remoteAddress.getPort());
        super.channelActive(ctx);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        // 1. 获取远程连接的地址信息
        InetSocketAddress remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress();
        // 2. 解绑通道：从连接管理器中移除该通道的绑定关系
        connectionManager.unbindChannel(ctx.channel());
        // 3. 记录日志：记录设备连接断开的信息
        log.info("设备连接断开 - 远程地址: {}:{}", remoteAddress.getHostString(), remoteAddress.getPort());
        // 4. 调用父类方法：确保事件能够继续在管道中传播
        super.channelInactive(ctx);
    }

    /**
     * 消息解码
     *
     * @param ctx 上下文，获取 Channel、Pipeline 或触发事件（如异常传递）
     * @param msg 消息
     */
    @Override
    public void channelRead0(ChannelHandlerContext ctx, JT808Message msg) throws Exception {
        // 消息头
        JT808Header header = msg.getHeader();
        // 消息ID
        int msgId = header.getMsgId();
        // 终端手机号
        String terminalPhone = header.getTerminalPhone();

        log.info("[业务解码器] - 收到消息: (消息ID: 0x{}, 终端手机号: {})",
                Integer.toHexString(msgId), terminalPhone);
        try {
            switch (msgId) {
                case JT808Protocol.MSG_ID_TERMINAL_REGISTER:    //终端注册 0x0100
                    //log.info("终端注册");
                    handleTerminalRegister(ctx, msg);
                    break;
                case JT808Protocol.MSG_ID_TERMINAL_AUTH:        //终端鉴权 0x0102
                    //log.info("终端鉴权");
                    handleTerminalAuth(ctx, msg);
                    break;
                case JT808Protocol.MSG_ID_LOCATION_REPORT:      //位置信息汇报 0x0200
                    //log.info("位置信息汇报");
                    handleLocationReport(ctx, msg);
                    break;
                case JT808Protocol.MSG_ID_HEARTBEAT:            //心跳 0x0002
                    //log.info("心跳");
                    handleHeartbeat(ctx, msg);
                    break;
//                case JT808Protocol.MSG_ID_SERVER_SET_PARAM: // 设置终端参数
//                    log.info("设置终端参数消息体");
//                    encodeSetTerminalParams(buf, (TerminalParamBody) body);
//                    break;
//                case JT808Protocol.MSG_ID_SERVER_SELECT_PARAM: // 查询终端参数
//                    log.info("查询终端参数消息体");
//                    encodeQueryTerminalParams(buf, (QueryParamBody) body);
//                    break;
                default:
                    log.info("未知消息");
                    handleUnknownMessage(ctx, msg);
            }
        } catch (Exception e) {
            log.error("[业务解码器]，处理消息失败 - 终端手机号: {}, 消息ID: 0x{}, 错误: {}",
                    terminalPhone, Integer.toHexString(header.getMsgId()), e.getMessage());
            // 消息处理失败，发送通用应答(0x8001)
            sendCommonResponse(ctx, header, (byte) 0x03);
            //关闭连接
            ctx.close();
        }
    }

    // ===================== 消息处理方法 ===================================================

    /**
     * 处理终端注册(0x0100)
     */
    public void handleTerminalRegister(ChannelHandlerContext ctx, JT808Message msg) {
        JT808Header header = msg.getHeader();
        RegisterBody body = (RegisterBody) msg.getBody();
        //终端ID
        String terminalId = body.getTerminalId();
        //手机号
        String terminalPhone = header.getTerminalPhone();

        try {
            // 1. 验证注册信息完整性 - 终端ID
            if (ObjectUtil.isEmpty(terminalId)) {
                log.error("终端注册失败, 终端ID不能为空,终端手机号: {}", terminalPhone);
                sendRegisterResponse(ctx, header, (byte) 0x04, "");
            }
            // 2. 验证注册信息完整性 - 手机号
            if (ObjectUtil.isEmpty(terminalPhone)) {
                log.error("终端注册失败, 终端手机号不能为空,终端ID: {}", terminalId);
                sendRegisterResponse(ctx, header, (byte) 0x04, "");
            }
            // 3. 检查终端是否已被注册
            DeviceVo deviceVo = terminalService.isRegister(terminalPhone);
            if (!ObjectUtil.isEmpty(deviceVo) && StringUtils.isNotEmpty(deviceVo.getAuthCode())) {
                // 绑定终端到通道
                connectionManager.bindTerminal(terminalPhone, ctx.channel());
                log.info("终端已经注册成功, 终端ID: {}, 终端手机号: {}, 鉴权码: {}",
                        terminalId, terminalPhone, deviceVo.getAuthCode());
                sendRegisterResponse(ctx, header, (byte) 0x00, deviceVo.getAuthCode());
            }
            // 4. 执行注册
            TerminalRegisterDto terminalRegisterDto = BeanUtil.copyProperties(body, TerminalRegisterDto.class);
            terminalRegisterDto.setTerminalPhone(terminalPhone);
            TerminalRegisterResult result = terminalService.registerTerminal(terminalRegisterDto);
            // 5. 发送注册响应
            if (result.isSuccess()) {
                // 绑定终端到通道
                connectionManager.bindTerminal(terminalPhone, ctx.channel());
                log.info("终端注册成功, 终端ID: {}, 终端手机号: {}, 鉴权码: {}",
                        terminalId, terminalPhone, result.getAuthCode());
                sendRegisterResponse(ctx, header, (byte) 0x00, result.getAuthCode());
            } else {
                log.warn("终端注册失败, 终端ID: {}, 终端手机号: {}, 原因: {}",
                        terminalId, terminalPhone, result.getErrorMessage());
                sendRegisterResponse(ctx, header, (byte) 0x01, "");
            }
        } catch (Exception e) {
            log.error("终端注册处理异常, 终端ID: {}, 终端手机号: {},错误: {}",
                    terminalId, terminalPhone, e.getMessage());
            sendRegisterResponse(ctx, header, (byte) 0x01, "");
        }
    }


    /**
     * 处理终端鉴权(0x0102)
     */
    public void handleTerminalAuth(ChannelHandlerContext ctx, JT808Message msg) {
        JT808Header header = msg.getHeader();
        AuthBody body = (AuthBody) msg.getBody();

        String terminalPhone = header.getTerminalPhone();
        String authCode = body.getAuthCode();
        log.info("终端手机号: {}, 鉴权码: {}", terminalPhone, authCode);

        // 1. 检查终端是否注册
        DeviceVo deviceVo = terminalService.isRegister(terminalPhone);
        if (ObjectUtil.isEmpty(deviceVo) || ObjectUtil.isEmpty(deviceVo.getAuthCode())) {
            log.error("终端鉴权失败, 终端未注册, 终端手机号: {}", terminalPhone);
            sendAuthResponse(ctx, header, (byte) 0x01);
        }
        // 2. 鉴权
        boolean authSuccess = terminalService.authenticateTerminal(header.getTerminalPhone(), body);
        if (authSuccess) {
            // 绑定终端到通道
            connectionManager.bindTerminal(terminalPhone, ctx.channel());

            log.info("终端鉴权成功, 终端手机号: {}", header.getTerminalPhone());
            sendAuthResponse(ctx, header, (byte) 0x00);
        } else {
            log.warn("终端鉴权失败, 终端手机号: {}", header.getTerminalPhone());
            // 鉴权失败
            sendAuthResponse(ctx, header, (byte) 0x01);
        }
    }

    /**
     * 处理位置上报(0x0200)
     */
    public void handleLocationReport(ChannelHandlerContext ctx, JT808Message msg) {
        JT808Header header = msg.getHeader();
        LocationBody body = (LocationBody) msg.getBody();
        String terminalPhone = header.getTerminalPhone();
        // 1.检查终端是否鉴权
        boolean isAlreadyRegistered = terminalService.isAuth(terminalPhone);
        if (!isAlreadyRegistered) {
            log.error("终端未鉴权, 终端手机号: {}", terminalPhone);
            sendRegisterResponse(ctx, header, (byte) 0x02, "");
        }
        try {
            // 1.处理位置上报
            terminalService.handleLocationReport(terminalPhone, body);
            // 2.处理报警信息（TODO）

            // 绑定终端到通道
            connectionManager.bindTerminal(terminalPhone, ctx.channel());

            log.info("位置上报处理完成, 终端: {}, 位置: ({}, {}), 速度: {}km/h",
                    terminalPhone, body.getLatitude(), body.getLongitude(), body.getSpeed());
            // 3.发送通用应答
            sendCommonResponse(ctx, header, (byte) 0x00);
        } catch (Exception e) {
            log.error("处理位置上报失败, 手机号: {},错误: {}", terminalPhone, e.getMessage());
        }
    }

    /**
     * 处理心跳(0x0002)
     */
    public void handleHeartbeat(ChannelHandlerContext ctx, JT808Message msg) {
        JT808Header header = msg.getHeader();
        String terminalPhone = header.getTerminalPhone();
        try {
            // 更新终端活跃时间
            terminalService.updateTerminalActiveTime(terminalPhone);
            // 检查终端是否已绑定
            if (connectionManager.getTerminal(ctx.channel()) == null) {
                // 如果未绑定，尝试绑定
                connectionManager.bindTerminal(terminalPhone, ctx.channel());
            }
            log.info("心跳处理成功 - 终端: {}", terminalPhone);
        } catch (Exception e) {
            log.error("心跳处理失败, 手机号: {}, 错误: {}", terminalPhone, e.getMessage());
        }
    }

    /**
     * 处理终端参数查询(0x0104)
     */
    public void handleTerminalParamQuery(ChannelHandlerContext ctx, JT808Message msg) {
        JT808Header header = msg.getHeader();
        // 实现参数查询逻辑
        log.info("终端参数查询 - 终端: {}", header.getTerminalPhone());
        sendCommonResponse(ctx, header, (byte) 0x00);
    }

    /**
     * 处理事件报告(0x0301)
     */
    public void handleEventReport(ChannelHandlerContext ctx, JT808Message msg) {
        JT808Header header = msg.getHeader();
        // 实现事件报告处理
        log.info("事件报告 - 终端: {}", header.getTerminalPhone());
        //sendCommonResponse(ctx, header, (byte) 0x00);
    }

    /**
     * 处理驾驶员信息(0x0704)
     */
    public void handleDriverInfo(ChannelHandlerContext ctx, JT808Message msg) {
        JT808Header header = msg.getHeader();
        // 实现驾驶员信息处理
        log.info("驾驶员信息采集 - 终端: {}", header.getTerminalPhone());
        //sendCommonResponse(ctx, header, (byte) 0x00);
    }

    /**
     * 处理未知消息
     */
    public void handleUnknownMessage(ChannelHandlerContext ctx, JT808Message msg) {
        JT808Header header = msg.getHeader();
        log.warn("未知消息类型 - 终端: {}, 消息ID: 0x{}",
                header.getTerminalPhone(), Integer.toHexString(header.getMsgId()));
        //sendCommonResponse(ctx, header, (byte) 0x03); // 不支持的消息类型
    }

    // ===================== 辅助方法 =====================

    /**
     * 发送注册应答(0x8100)
     */
    public void sendRegisterResponse(ChannelHandlerContext ctx,
                                     JT808Header requestHeader,
                                     byte result,
                                     String authCode) {
        log.info("发送注册应答");
        try {
            // 创建响应头 - 不要修改原始请求头
            JT808Header header = new JT808Header();
            header.setMsgId(0x8100);                                     // 注册应答消息ID(2字节)
            header.setTerminalPhone(requestHeader.getTerminalPhone());   // 终端手机号(10字节)
            header.setFlowId(requestHeader.getFlowId());                 // 流水号(2字节)
            header.setVersion(1);                                        // 版本号(1字节)
            // 计算消息体长度
            // 应答流水号(2) + 结果(1) + 鉴权码
            int bodyLength = calculateBodyLength(result, authCode);
            header.setMsgBodyLength(bodyLength);
            // 计算消息体属性
            short msgBodyProps = JT808BodyPropsUtil.buildBodyProps2019(bodyLength, 0, false, true);
            header.setMsgBodyProps(msgBodyProps);
            // 注册应答消息体
            RegisterResponse response = new RegisterResponse();
            response.setResponseFlowId(requestHeader.getFlowId());                // 应答流水号 (2字节)
            response.setResult(result);                                           // 0-成功 1-失败 (2字节)
            response.setAuthCode(result == 0x00 ? authCode : "");                 // 鉴权码
            //完整消息
            JT808Message message = new JT808Message();
            message.setHeader(header);
            message.setBody(response);

            //log.info("平台发送注册应答消息: {}", message);

            // 直接发送JT808Message对象，编码器会自动处理编码
            boolean active = ctx.channel().isActive();
            //log.info("通道信息: {}", ctx.channel());
            //log.info("通道状态: {}", active);
            // 发送消息并添加监听器
            ChannelFuture future = ctx.channel().writeAndFlush(message);

            // 添加发送结果监听器
            future.addListener((ChannelFutureListener) f -> {
                if (f.isSuccess()) {
                    log.info("注册应答发送成功, 终端: ");
                    // 可以在这里执行发送成功后的操作
                } else {
                    log.error("注册应答发送失败, 错误: {}", f.cause().getMessage());
                    // 发送失败，可以尝试重发或记录错误
                    //handleSendFailure(response, f.cause());
                }
            });
        } catch (Exception e) {
            log.error("注册应答发送失败, 终端: {}, 错误: {}",
                    requestHeader.getTerminalPhone(), e.getMessage(), e);
        }
    }

    /**
     * 发送鉴权应答(0x8001)
     *
     * @param ctx           通道上下文
     * @param requestHeader 请求头
     * @param result        结果代码 (0-成功, 1-失败)
     */
    public void sendAuthResponse(ChannelHandlerContext ctx,
                                 JT808Header requestHeader,
                                 byte result) {
        log.info("发送鉴权应答");

        try {
            JT808Header header = new JT808Header();
            header.setMsgId(0x8001); // 通用应答消息ID
            header.setTerminalPhone(requestHeader.getTerminalPhone());
            header.setFlowId(requestHeader.getFlowId());
            // 版本号
            header.setVersion(requestHeader.getVersion());
            // 消息体长度固定为5字节
            int bodyLength = 5;
            header.setMsgBodyLength(bodyLength);
            // 根据协议版本构建消息体属性
            short msgBodyProps = JT808BodyPropsUtil.buildBodyProps2019(bodyLength, 0, false, true);
            header.setMsgBodyProps(msgBodyProps);

            CommonResponse response = new CommonResponse();
            response.setResponseFlowId(requestHeader.getFlowId());  // 对应终端的流水号
            response.setResponseMsgId(requestHeader.getMsgId());    // 对应终端的消息ID
            response.setResult(result);                             // 结果

            JT808Message message = new JT808Message();
            message.setHeader(header);
            message.setBody(response);

            //log.info("平台发送鉴权应答消息: {}", message);

            // 直接发送JT808Message对象，编码器会自动处理编码
            boolean active = ctx.channel().isActive();
            //log.info("通道信息: {}", ctx.channel());
            //log.info("通道状态: {}", active);
            // 发送消息并添加监听器
            ChannelFuture future = ctx.channel().writeAndFlush(message);

            // 添加发送结果监听器
            future.addListener((ChannelFutureListener) f -> {
                if (f.isSuccess()) {
                    log.info("鉴权应答发送成功, 终端: ");
                    // 可以在这里执行发送成功后的操作
                } else {
                    log.error("鉴权应答发送失败, 错误: {}", f.cause().getMessage());
                    // 发送失败，可以尝试重发或记录错误
                    //handleSendFailure(response, f.cause());
                }
            });
        } catch (Exception e) {
            log.error("鉴权应答发送失败，终端: {}, 错误: {}",
                    requestHeader.getTerminalPhone(), e.getMessage());
        }
    }


    /**
     * 发送通用应答(0x8001)
     */
    public void sendCommonResponse(ChannelHandlerContext ctx, JT808Header requestHeader, byte result) {

        log.info("发送通用应答");
        try {
            JT808Header header = new JT808Header();
            header.setMsgId(0x8001);                                    // 通用应答
            header.setTerminalPhone(requestHeader.getTerminalPhone());  // 终端手机号(10字节)
            header.setFlowId(requestHeader.getFlowId());                // 流水号(2字节)
            header.setVersion(1);                                       // 版本号(1字节)

            // 计算消息体长度
            // 应答的消息ID (2字节) + 应答流水号(2字节) + 结果(1字节)
            int bodyLength = 5;
            header.setMsgBodyLength(bodyLength);

            // 计算消息体属性
            short msgBodyProps = JT808BodyPropsUtil.buildBodyProps2019(bodyLength, 0, false, true);
            header.setMsgBodyProps(msgBodyProps);

            CommonResponse response = new CommonResponse();
            response.setResponseMsgId(requestHeader.getMsgId());    // 对应终端的消息ID
            response.setResponseFlowId(requestHeader.getFlowId());  // 对应终端的流水号
            response.setResult(result);                             // 结果

            JT808Message message = new JT808Message();
            message.setHeader(header);
            message.setBody(response);

            //log.info("平台发送应答消息: {}", message);

            // 直接发送JT808Message对象，编码器会自动处理编码
            boolean active = ctx.channel().isActive();
            //log.info("通道信息: {}", ctx.channel());
            //log.info("通道状态: {}", active);

            // 发送消息并添加监听器
            ChannelFuture future = ctx.channel().writeAndFlush(message);

            // 添加发送结果监听器
            future.addListener((ChannelFutureListener) f -> {
                if (f.isSuccess()) {
                    log.info("通用应答发送成功, 终端: ");
                    // 可以在这里执行发送成功后的操作
                } else {
                    log.error("通用应答发送失败, 错误: {}", f.cause().getMessage());
                    // 发送失败，可以尝试重发或记录错误
                    //handleSendFailure(response, f.cause());
                }
            });
        } catch (Exception e) {
            log.error("通用应答发送失败，终端: {}, 错误: {}",
                    requestHeader.getTerminalPhone(), e.getMessage());
        }
    }

    /**
     * 计算消息体长度
     */
    public int calculateBodyLength(byte result, String authCode) {
        // 固定部分: 应答流水号(2字节) + 结果(1字节)
        int length = 3;
        // 成功时添加鉴权码长度
        if (result == 0 && authCode != null && !authCode.isEmpty()) {
            try {
                length += authCode.getBytes("GBK").length;
            } catch (Exception e) {
                // 如果GBK编码失败，使用UTF-8编码
                length += authCode.getBytes(StandardCharsets.UTF_8).length;
            }
        }
        return length;
    }


    // ===================== 生命周期方法 =====================

    /**
     * 通道异常
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        // 解绑通道
        connectionManager.unbindChannel(ctx.channel());
        log.error("通道异常 - 地址: {}", ctx.channel().remoteAddress(), cause);
        ctx.close();
    }


}
